package de.claaswilke.presents.ui;

import java.io.IOException;
import java.util.Map;

import org.claaswilke.presents.ilp.IlpGenerator;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jface.action.ContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.ui.IActionDelegate;
import org.eclipse.ui.internal.Workbench;

import de.claaswilke.presents.PastPresent;
import de.claaswilke.presents.PastPresentRule;
import de.claaswilke.presents.Person;
import de.claaswilke.presents.PresentGroup;
import de.claaswilke.presents.PresentsFactory;
import de.claaswilke.presents.resource.presents.ui.PresentsUIPlugin;

/**
 * First version of menu item to trigger present combination combination
 * creation.
 * 
 * @author Claas Wilke
 */
public class ComputeCombinationsAction extends ContributionItem implements
		IActionDelegate {

	/** The currently selected {@link IResource}. */
	private IResource selectedResource = null;

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
	 */
	public void run(IAction action) {

		String errorMsg = null;

		if (selectedResource != null) {

			/* Load the test model. */
			try {
				ResourceSet rs = new ResourceSetImpl();

				String testModelPath = selectedResource.getFullPath().toFile()
						.toString();
				Resource resource = rs.createResource(URI
						.createFileURI(testModelPath));
				resource.load(null);

				EObject root = resource.getContents().get(0);

				/* Trigger code generation. */
				if (root instanceof PresentGroup) {
					PresentGroup group = (PresentGroup) root;

					String ilp = IlpGenerator.generateILP(group);
					
					System.out.println(ilp);
					
					Map<String, String> combinations = IlpGenerator.runILP(ilp);

					StringBuilder msg = new StringBuilder();
					msg.append("Computed the following combinations:\n\n");
					for (String from : combinations.keySet()) {
						msg.append(from + " -> " + combinations.get(from)
								+ ".\n");
					}

					MessageDialog dialog = new MessageDialog(Workbench
							.getInstance().getActiveWorkbenchWindow()
							.getShell(), "Result", null, msg.toString(),
							MessageDialog.NONE, new String[] { "OK",
									"Add to past present rules" }, 0);
					int returnCode = dialog.open();

					/* Probably add result to past present rules. */
					if (returnCode == 1) {
						for (String from : combinations.keySet()) {
							PastPresent pastPresent = findPastPresent(from,
									group);

							if (null == pastPresent) {
								pastPresent = PresentsFactory.eINSTANCE
										.createPastPresent();
								pastPresent.setFrom(findPerson(from, group));
								group.getPastPresents().add(pastPresent);
							}
							// no else.

							PastPresentRule rule = findPastPresentRule(
									pastPresent.getTo(), combinations.get(from));

							if (null == rule) {
								rule = PresentsFactory.eINSTANCE
										.createPastPresentRule();
								rule.setPerson(findPerson(combinations.get(from), group));
								pastPresent.getTo().add(rule);
							}

							else {
								Integer multiplicator = rule.getMultiplicator();

								if (null == multiplicator)
									multiplicator = 2;
								else
									multiplicator++;

								rule.setMultiplicator(multiplicator);
							}
						}
						// end for.

						group.eResource().save(null);
					}
					// no else.
				}

				else
					errorMsg = "Root element of Present program is not a PresentGroup.";
			}

			catch (IOException e1) {
				errorMsg = "Exception during loading of test model resource: "
						+ e1.getMessage();
			}

			if (errorMsg != null) {
				ErrorDialog dialog = new ErrorDialog(PresentsUIPlugin
						.getDefault().getWorkbench().getActiveWorkbenchWindow()
						.getShell(), "Present combination computation failed.",
						errorMsg, new Status(IStatus.ERROR,
								PresentsUIPlugin.PLUGIN_ID, errorMsg), SWT.NONE);
				dialog.open();
			}
			// no else.
		}
	}

	/**
	 * Helper method to find a {@link PastPresentRule} that matches to a given
	 * {@link Person}.
	 * 
	 * @param rules
	 *            A list of {@link PastPresentRule}s to be searched.
	 * @param personName
	 *            The name of the {@link Person} to be found.
	 * @return The found {@link PastPresentRule} or <code>null</code>.
	 */
	private PastPresentRule findPastPresentRule(EList<PastPresentRule> rules,
			String personName) {

		for (PastPresentRule rule : rules) {
			if (rule.getPerson().getIdentifier().equals(personName))
				return rule;
			// no else.
		}
		// end for.

		return null;
	}

	/**
	 * Helper method to find a {@link Person} in a given {@link PresentGroup}.
	 * 
	 * @param name
	 *            The name of the {@link Person} to be found.
	 * @param group
	 *            The {@link PresentGroup}.
	 * @return The found {@link Person} or null.
	 */
	private Person findPerson(String name, PresentGroup group) {

		for (Person person : group.getPersons()) {
			if (person.getIdentifier().equals(name))
				return person;
			// no else.
		}
		// end for.

		return null;
	}

	/**
	 * Helper method to find a {@link PastPresent} rule for a given person in a
	 * given {@link PresentGroup}.
	 * 
	 * @param from
	 *            The name of the {@link Person}.
	 * @param group
	 *            The {@link PresentGroup}.
	 * @return The found {@link PastPresent} rule or <code>null</code>.
	 */
	private PastPresent findPastPresent(String from, PresentGroup group) {

		for (PastPresent pastPresent : group.getPastPresents()) {
			if (pastPresent.getFrom().getIdentifier().equals(from))
				return pastPresent;
			// no else.
		}
		// end for.

		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action
	 * .IAction, org.eclipse.jface.viewers.ISelection)
	 */
	public void selectionChanged(IAction action, ISelection selection) {
		String errorMsg = null;

		/* Get the current selection. */
		if (selection instanceof IStructuredSelection) {
			IStructuredSelection currentSelection = (IStructuredSelection) selection;

			/* The select object must be a test model. */
			Object selectedObject = currentSelection.getFirstElement();

			if (selectedObject instanceof IResource)
				selectedResource = (IResource) selectedObject;

			else if (null != selectedObject)
				errorMsg = "Wrong type of selected element. Expected IResource but was: "
						+ selectedObject.getClass().getCanonicalName() + ".";
			// no else.
		}

		else
			errorMsg = "Wrong type of selected element. Expected IStructuredSelection but was: "
					+ selection.getClass().getCanonicalName() + ".";

		if (errorMsg != null) {
			ErrorDialog dialog = new ErrorDialog(PresentsUIPlugin.getDefault()
					.getWorkbench().getActiveWorkbenchWindow().getShell(),
					"Present combination computetion failed.", errorMsg,
					new Status(IStatus.ERROR, PresentsUIPlugin.PLUGIN_ID,
							errorMsg), SWT.NONE);
			dialog.open();
		}
		// no else.
	}
}
